﻿using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Wedn.Net.Route
{
    /// <summary>
    /// 自定义路由类(支持二级域名)
    /// </summary>
    public class WednRoute : System.Web.Routing.Route
    {
        #region Field
        private Regex _domainRegex;
        private Regex _pathRegex;
        #endregion

        #region Property
        /// <summary>
        /// 域名
        /// </summary>
        public string Domain { get; set; }
        #endregion

        #region Constructor
        /// <summary>
        /// 自定义路由构造函数
        /// </summary>
        /// <param name="url"></param>
        /// <param name="routeHandler"></param>
        public WednRoute(string url, IRouteHandler routeHandler) : base(url, routeHandler) { }

        /// <summary>
        /// 自定义路由构造函数
        /// </summary>
        /// <param name="domain"></param>
        /// <param name="url"></param>
        /// <param name="defaults"></param>
        public WednRoute(string domain, string url, RouteValueDictionary defaults) : base(url, defaults, new MvcRouteHandler()) { Domain = domain; }

        /// <summary>
        /// 自定义路由构造函数
        /// </summary>
        /// <param name="domain"></param>
        /// <param name="url"></param>
        /// <param name="defaults"></param>
        public WednRoute(string domain, string url, object defaults) : base(url, new RouteValueDictionary(defaults), new MvcRouteHandler()) { Domain = domain; }

        /// <summary>
        /// 自定义路由构造函数
        /// </summary>
        /// <param name="domain"></param>
        /// <param name="url"></param>
        /// <param name="defaults"></param>
        /// <param name="constraints"></param>
        public WednRoute(string domain, string url, RouteValueDictionary defaults, RouteValueDictionary constraints) : base(url, defaults, constraints, new MvcRouteHandler()) { Domain = domain; }

        /// <summary>
        /// 自定义路由构造函数
        /// </summary>
        /// <param name="domain"></param>
        /// <param name="url"></param>
        /// <param name="defaults"></param>
        /// <param name="constraints"></param>
        /// <param name="routeHandler"></param>
        public WednRoute(string domain, string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler) : base(url, defaults, constraints, routeHandler) { Domain = domain; }
        #endregion

        /// <summary>
        /// 自定义路由构造函数
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            // 构造 regex
            _domainRegex = CreateRegex(Domain) ?? new Regex(".");
            _pathRegex = CreateRegex(Url) ?? new Regex(".");

            // 请求信息
            var requestDomain = httpContext.Request.Headers["host"];
            if (!string.IsNullOrEmpty(requestDomain))
            {
                if (requestDomain.IndexOf(":", System.StringComparison.Ordinal) > 0)
                {
                    requestDomain = requestDomain.Substring(0, requestDomain.IndexOf(":", System.StringComparison.Ordinal));
                }
            }
            else
            {
                if (httpContext.Request.Url != null) requestDomain = httpContext.Request.Url.Host;
            }
            string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;

            // 匹配域名和路由
            var domainMatch = _domainRegex.Match(requestDomain);
            var pathMatch = _pathRegex.Match(requestPath);

            // 路由数据
            if (!domainMatch.Success || !pathMatch.Success) return null;
            var data = new RouteData(this, RouteHandler);

            // 添加默认选项
            if (Defaults != null)
            {
                foreach (var item in Defaults)
                {
                    data.Values[item.Key] = item.Value;
                    if (item.Key.Equals("area") || item.Key.Equals("Namespaces"))
                    {
                        data.DataTokens[item.Key] = item.Value;
                    }
                }
            }

            // 匹配域名路由
            for (var i = 1; i < domainMatch.Groups.Count; i++)
            {
                var group = domainMatch.Groups[i];
                if (!@group.Success) continue;
                var key = _domainRegex.GroupNameFromNumber(i);

                if (string.IsNullOrEmpty(key) || char.IsNumber(key, 0)) continue;
                if (string.IsNullOrEmpty(@group.Value)) continue;
                data.Values[key] = @group.Value;
                if (key.Equals("area"))
                {
                    data.DataTokens[key] = @group.Value;
                }
            }

            // 匹配域名路径
            for (int i = 1; i < pathMatch.Groups.Count; i++)
            {
                var group = pathMatch.Groups[i];
                if (!@group.Success) continue;
                var key = _pathRegex.GroupNameFromNumber(i);

                if (string.IsNullOrEmpty(key) || char.IsNumber(key, 0)) continue;
                if (string.IsNullOrEmpty(@group.Value)) continue;
                data.Values[key] = @group.Value;
                if (key.Equals("area"))
                {
                    data.DataTokens[key] = @group.Value;
                }
            }

            return data;
            //return base.GetRouteData(httpContext);
        }

        /// <summary>
        /// 获取虚拟路径
        /// </summary>
        /// <param name="requestContext"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            return base.GetVirtualPath(requestContext, RemoveDomainTokens(values));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="requestContext"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public DomainData GetDomainData(RequestContext requestContext, RouteValueDictionary values)
        {
            // 获得主机名
            var hostname = values.Aggregate(Domain, (current, pair) => current.Replace("{" + pair.Key + "}", pair.Value.ToString()));

            // Return 域名数据
            return new DomainData
            {
                Protocol = "http",
                HostName = hostname,
                Fragment = string.Empty
            };
        }

        private Regex CreateRegex(string source)
        {
            if (string.IsNullOrEmpty(source)) return null;
            // 替换
            source = source.Replace("/", @"\/?");
            source = source.Replace(".", @"\.?");
            source = source.Replace("-", @"\-?");
            source = source.Replace("{", @"(?<");
            source = source.Replace("}", @">([a-zA-Z0-9_]*))");

            return new Regex("^" + source + "$");
        }

        private RouteValueDictionary RemoveDomainTokens(RouteValueDictionary values)
        {
            var tokenRegex = new Regex(@"({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?");
            var tokenMatch = tokenRegex.Match(Domain);
            for (var i = 0; i < tokenMatch.Groups.Count; i++)
            {
                var group = tokenMatch.Groups[i];
                if (!@group.Success) continue;
                var key = @group.Value.Replace("{", "").Replace("}", "");
                if (values.ContainsKey(key))
                    values.Remove(key);
            }

            return values;
        }
    }
    /// <summary>
    /// 
    /// </summary>
    public class DomainData
    {
        /// <summary>
        /// 
        /// </summary>
        public string Protocol { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string HostName { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string Fragment { get; set; }
    }
}